import logging
import os
import sys
import atexit

# 确保日志目录存在
LOG_DIR = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'logs')
if not os.path.exists(LOG_DIR):
    try:
        os.makedirs(LOG_DIR)
    except Exception as e:
        with open(os.path.join(os.path.dirname(os.path.abspath(__file__)), 'fatal.log'), 'w') as f:
            f.write(f"无法创建日志目录: {str(e)}\n")
        sys.exit(1)

# 紧急日志文件 - 记录最关键的启动信息
EMERGENCY_LOG = os.path.join(LOG_DIR, 'emergency.log')
STARTUP_LOG = os.path.join(LOG_DIR, 'startup_errors.log')

# 清理函数
def cleanup():
    logging.shutdown()
atexit.register(cleanup)

try:
    # 紧急日志检查
    with open(EMERGENCY_LOG, 'w', encoding='utf-8') as f:
        f.write(f"程序启动中... PID: {os.getpid()}\n详细启动日志请查看: {STARTUP_LOG}\n")

    # 初始化日志系统
    logging.basicConfig(encoding='utf-8', 
        filename=STARTUP_LOG,
        level=logging.DEBUG,
        format='%(asctime)s - %(levelname)s - %(module)s:%(lineno)d - %(message)s',
        filemode='w'
    )
    logging.debug("日志系统初始化成功")
    logging.debug("开始创建Tkinter主窗口...")

    # 验证uploads目录
    UPLOADS_DIR = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'uploads')
    if not os.path.exists(UPLOADS_DIR):
        logging.debug("创建uploads目录")
        os.makedirs(UPLOADS_DIR)
    else:
        logging.debug("uploads目录已存在")

    # 导入核心模块
    logging.debug("开始导入核心模块...")
    try:
        import socket
        import struct
        import json
        import threading
        import http.client
        import http.server
        import socketserver
        import time
        from queue import Queue
        logging.debug("核心模块导入成功")
    except ImportError as e:
        logging.critical(f"核心模块导入失败: {str(e)}", exc_info=True)
        sys.exit(1)

    # 初始化全局日志队列
    log_queue = Queue()

    # 导入Tkinter模块
    logging.debug("开始导入Tkinter...")
    try:
        import tkinter as tk
        import tkinter.messagebox as messagebox
        logging.debug("Tkinter导入成功")
    except ImportError as e:
        logging.critical(f"Tkinter模块导入失败: {str(e)}", exc_info=True)
        sys.exit(1)

    # 配置常量
    logging.debug("开始定义常量...")
    HTTP_SERVER_PORT = 8001
    TARGET_DEVICE_IP = "192.168.1.100"
    MULTICAST_GROUP_IP = '224.0.0.251'
    MULTICAST_PORT = 5000
    OTA_TRIGGER_PORT = 8080
    OTA_FILENAME = 'ota.bin'
    OTA_FILEPATH = os.path.join(UPLOADS_DIR, OTA_FILENAME)
    logging.debug(f"常量定义完成: HTTP_SERVER_PORT={HTTP_SERVER_PORT}, TARGET_DEVICE_IP={TARGET_DEVICE_IP}")

    # 初始化日志队列
    logging.debug("初始化日志队列...")
    log_queue = Queue()

    # 定义日志函数
    def log_message(message):
        global log_queue
        log_queue.put(message)
        logging.debug(f"日志消息: {message}")
    logging.debug("日志函数定义完成")

    # 多播接收线程
    def multicast_listener():
        global current_version, new_version
        try:
            sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP)
            sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
            sock.bind(('', MULTICAST_PORT))
            group = socket.inet_aton(MULTICAST_GROUP_IP)
            mreq = struct.pack('4sL', group, socket.INADDR_ANY)
            sock.setsockopt(socket.IPPROTO_IP, socket.IP_ADD_MEMBERSHIP, mreq)
            log_message(f"Listening for multicast messages on {MULTICAST_GROUP_IP}:{MULTICAST_PORT}...")
            
            try:
                while True:
                    data, addr = sock.recvfrom(1024)
                    log_message(f"Received message from {addr}:")
                    try:
                        json_data = json.loads(data.decode('utf-8'))
                    except UnicodeDecodeError:
                        log_message("Received message cannot be decoded as UTF-8")
                        continue
                    ota_state = json_data.get('OTA_state')
                    ota_version = json_data.get('OTA_version')
                    if ota_state and ota_version:
                        log_message(f"OTA State: {ota_state}, Version: {ota_version}")
                        # 如果是首次获取版本信息
                        if current_version is None:
                            current_version = ota_version
                            log_message(f"Initial Version: {current_version}")
                        else:
                            # 检查版本号是否更新
                            new_version = ota_version
                            log_message(f"New Version: {new_version}")
                            # 比较版本号
                            if new_version > current_version:
                                log_message("Upgrade successful")
                            else:
                                log_message("Upgrade failed or version unchanged")
                    else:
                        log_message("Received message is not in the expected format")
            except json.JSONDecodeError:
                log_message("Received message is not valid JSON")
            log_message("")  # 添加一个空行以便阅读
        except KeyboardInterrupt:
            log_message("Exiting...")
        finally:
            sock.setsockopt(socket.IPPROTO_IP, socket.IP_DROP_MEMBERSHIP, mreq)
            sock.close()

    # HTTP服务器部分
    class MyHttpRequestHandler(http.server.SimpleHTTPRequestHandler):
        def log_message(self, format, *args):
            try:
                message = format % args
                log_message(f"HTTP Server: {message}")
            except:
                log_message(f"HTTP Server: Error formatting log message")
        def do_GET(self):
            if self.path == '/api/uploadfile':
                if not os.path.exists(OTA_FILEPATH):
                    self.send_error(404, 'File Not Found')
                    return

                file_size = os.path.getsize(OTA_FILEPATH)
                self.send_response(200)
                self.send_header('Content-Disposition', f'attachment; filename="{OTA_FILENAME}"')
                self.send_header('Content-Type', 'application/octet-stream')
                self.send_header('Content-Length', file_size)
                self.end_headers()

                bytes_sent = 0
                with open(OTA_FILEPATH, 'rb') as f:
                    while True:
                        chunk = f.read(4096)
                        if not chunk:
                            break
                        bytes_sent += len(chunk)
                        progress = (bytes_sent / file_size) * 100
                        log_message(f"Sending {len(chunk)} bytes... ({progress:.2f}%)")
                        self.wfile.write(chunk)
                log_message("File download complete")
            else:
                super().do_GET()

    # HTTP客户端部分
    def trigger_ota(target_ip):
        try:
            conn = http.client.HTTPConnection(f'{target_ip}:{OTA_TRIGGER_PORT}')
            conn.request('POST', '/ota-start', body='start_ota', headers={'Content-Type': 'text/plain'})
            response = conn.getresponse()
            log_message(f'Status: {response.status}, Response: {response.read().decode()}')
            conn.close()
        except Exception as e:
            log_message(f'Error occurred: {e}')

        log_message("")

    def run_server():
        try:
            server = socketserver.TCPServer(('', HTTP_SERVER_PORT), MyHttpRequestHandler)
            log_message(f"Server started on port {HTTP_SERVER_PORT}")
            server.serve_forever()
        except Exception as e:
            log_message(f"服务器线程错误: {str(e)}")

except Exception as e:
    logging.critical(f"全局初始化失败: {str(e)}", exc_info=True)
    sys.exit(1)

if __name__ == '__main__':
    try:
        # 创建 Tkinter 主窗口
        logging.debug("正在创建Tkinter主窗口...")
        root = tk.Tk()
        root.title("科奈信8735B升级程序")
        root.geometry("600x400")

        # 创建日志显示区域
        log_frame = tk.Frame(root)
        log_frame.pack(fill=tk.BOTH, expand=True, padx=10, pady=10)

        log_label = tk.Label(log_frame, text="运行日志:")
        log_label.pack(anchor=tk.W)

        # 添加滚动条
        scrollbar = tk.Scrollbar(log_frame)
        scrollbar.pack(side=tk.RIGHT, fill=tk.Y)

        # 创建文本控件用于显示日志
        log_text = tk.Text(log_frame, wrap=tk.WORD, state=tk.DISABLED, yscrollcommand=scrollbar.set)
        log_text.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)
        scrollbar.config(command=log_text.yview)

        # 日志更新函数
        def update_log():
            global log_queue
            while not log_queue.empty():
                message = log_queue.get()
                log_text.config(state=tk.NORMAL)
                log_text.insert(tk.END, message + '\n')
                log_text.config(state=tk.DISABLED)
                log_text.see(tk.END)  # 滚动到最新内容
            root.after(100, update_log)

        # 启动日志更新
        update_log()

        # 创建 uploads 文件夹
        if not os.path.exists('uploads'):
            os.makedirs('uploads')

        # 启动多播接收线程
        multicast_thread = threading.Thread(target=multicast_listener)
        multicast_thread.daemon = True
        multicast_thread.start()
        log_message("Started multicast listener thread")

        # 启动HTTP服务器
        server_thread = threading.Thread(target=run_server)
        server_thread.daemon = True
        server_thread.start()

        # 等待一会儿让多播线程初始化并接收初始版本信息
        log_message("Waiting for initial version information...")
        root.after(2000, lambda: trigger_ota(TARGET_DEVICE_IP))
        log_message("Triggering OTA update...")

        # 等待一会儿让设备完成升级
        def finish_upgrade():
            log_message("Waiting for device to complete upgrade...")
        root.after(12000, finish_upgrade)

        logging.debug("即将进入Tkinter主循环...")
        root.mainloop()
        logging.debug("Tkinter主循环退出")
    except KeyboardInterrupt:
        log_message("\nServer shutting down.")
    except Exception as e:
        # 尝试使用现有root窗口显示错误
        if 'root' in locals() and root.winfo_exists():
            root.withdraw()
            messagebox.showerror("启动错误", f"程序启动失败: {str(e)}", parent=root)
        else:
            # 创建临时Tk实例显示错误
            try:
                error_root = tk.Tk()
                error_root.withdraw()
                messagebox.showerror("严重错误", f"程序启动失败: {str(e)}\n详细信息已记录到logs/startup_errors.log")
                error_root.destroy()
            except Exception as msgbox_err:
                with open(STARTUP_LOG, 'a') as f:
                    f.write(f"无法显示错误对话框: {str(msgbox_err)}\n")
                exit(1)

